package me.flyray.gate.filter;

import me.flyray.auth.client.jwt.UserAuthUtil;
import me.flyray.auth.common.bean.UserJWTInfo;
import me.flyray.auth.common.config.UserAuthConfig;
import me.flyray.auth.common.util.jwt.IJWTInfo;
import me.flyray.common.context.BaseContextHandler;
import me.flyray.common.msg.ResponseCode;
import me.flyray.common.util.ClientUtil;
import me.flyray.common.vo.LogInfo;
import me.flyray.common.vo.PermissionInfo;
import me.flyray.gate.feign.ILogService;
import me.flyray.gate.feign.IUserService;
import me.flyray.gate.utils.DBLog;
import me.flyray.gate.utils.FilterUrlUtils;
import me.flyray.gate.utils.RequestExceptionUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * ${DESCRIPTION}
 * 管理后台拦截器
 */
@Component
@Slf4j
public class AdminAccessFilter extends ZuulFilter {
	@Autowired
	@Lazy
	private IUserService userService;
	@Autowired
	@Lazy
	private ILogService logService;
	@Autowired
	private UserAuthUtil userAuthUtil;

	@Autowired
	private UserAuthConfig userAuthConfig;
	@Autowired
	private FilterUrlUtils filterUrlUtils;
    @Value("${zuul.prefix}")
    private String zuulPrefix;
	@Override
	public String filterType() {
		return "pre";
	}

	@Override
	public int filterOrder() {
		return 2;
	}

	@Override
	public boolean shouldFilter() {
		return !filterUrlUtils.filterIgnoreUrl(0)&&!filterUrlUtils.filterIgnoreUrl(1);
	}

	@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
		final String requestUri = request.getRequestURI().substring(zuulPrefix.length());
		final String method = request.getMethod();
        String authToken = request.getHeader(userAuthConfig.getTokenHeader());
        ctx.addZuulRequestHeader(userAuthConfig.getTokenHeader(), authToken);
        BaseContextHandler.setToken(authToken);
        IJWTInfo user = new UserJWTInfo(BaseContextHandler.getPlatformId(),BaseContextHandler.getName(),BaseContextHandler.getXId());
		//查询出所有菜单权限
		List<PermissionInfo> permissionIfs = userService.getAllPermissionInfo();
		// 判断资源是否启用权限约束
		Stream<PermissionInfo> stream = getPermissionIfs(requestUri, method, permissionIfs);
		//把stream中的元素转换成List
		List<PermissionInfo> result = stream.collect(Collectors.toList());
		PermissionInfo[] permissions = result.toArray(new PermissionInfo[]{});
		//permissions.length > 0 说明请求路由需要授权 匹配上的请求路由需要判断是否给用户授权没有给返回未授权
		if (permissions.length > 0) {
			checkUserPermission(permissions, ctx, user);
		}
		return null;
	}

	/**
	 * 获取目标权限资源
	 *
	 * @param requestUri
	 * @param method
	 * @param serviceInfo
	 * @return
	 */
	private Stream<PermissionInfo> getPermissionIfs(final String requestUri, final String method, List<PermissionInfo> serviceInfo) {
		return serviceInfo.parallelStream().filter(new Predicate<PermissionInfo>() {
			@Override
			public boolean test(PermissionInfo permissionInfo) {
				String url = permissionInfo.getUri();
				String uri = url.replaceAll("\\{\\*\\}", "[a-zA-Z\\\\d]+");
				String regEx = "^" + uri + "$";
				if (Pattern.compile(regEx).matcher(requestUri).find() || (requestUri.startsWith(url + "/"))
						&& method.equals(permissionInfo.getMethod())) {
					log.info("requestUri-------{}",requestUri + "=======" + regEx);
					log.info("uri正则匹配---------{}",Pattern.compile(regEx).matcher(requestUri).find());
					log.info("uri正则匹配---------{}",(requestUri.startsWith(url + "/")&& method.equals(permissionInfo.getMethod())));
				}
				return (Pattern.compile(regEx).matcher(requestUri).find() || (requestUri.startsWith(url + "/"))
						&& method.equals(permissionInfo.getMethod()));
			}
		});
	}
	

	private void setCurrentUserInfoAndLog(RequestContext ctx, IJWTInfo user, PermissionInfo pm) {
		String host = ClientUtil.getClientIp(ctx.getRequest());
		ctx.addZuulRequestHeader("userId", user.getXId());
		ctx.addZuulRequestHeader("userName", URLEncoder.encode(user.getName()));
		ctx.addZuulRequestHeader("userHost", ClientUtil.getClientIp(ctx.getRequest()));
		LogInfo logInfo = new LogInfo(user.getPlatformId() ,pm.getMenu(), pm.getName(), pm.getUri(), new Date(), user.getXId(), user.getName(), host);
		DBLog.getInstance().setLogService(logService).offerQueue(logInfo);
	}

	private void checkUserPermission(PermissionInfo[] permissions, RequestContext ctx, IJWTInfo user) {
		//查询出登陆用户所具有的菜单权限
		List<PermissionInfo> permissionInfos = userService.getPermissionByUsername(user.getName());
		PermissionInfo current = null;
		for (PermissionInfo info : permissions) {
			boolean anyMatch = permissionInfos.parallelStream().anyMatch(new Predicate<PermissionInfo>() {
				@Override
				public boolean test(PermissionInfo permissionInfo) {
					return permissionInfo.getCode().equals(info.getCode());
				}
			});
			if (anyMatch) {
				current = info;
				break;
			}
		}
		//提示登陆用户暂无权限
		if (current == null) {
			RequestExceptionUtils.setFailedRequest(ResponseCode.USER_NO_MENU_AUTH.getCode(),ResponseCode.USER_NO_MENU_AUTH.getMessage());
		} else {
			if (!RequestMethod.GET.toString().equals(current.getMethod())) {
				setCurrentUserInfoAndLog(ctx, user, current);
			}
		}
	}

}
